package com.suxin.service;

import com.google.common.collect.Lists;
import com.suxin.domain.Good;
import com.suxin.domain.UserInfo;
import com.suxin.enums.GoodType;
import com.suxin.exception.GoodException;
import com.suxin.exception.GoodExceptionOver;
import com.suxin.mapper.GoodsMapper;
import com.suxin.utils.ExceptionUtils;
import lombok.Setter;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * @author Tang
 * @classname GoodServiceImpl
 * @description [  ]
 * @date 2021/6/25 14:32
 */
@Service
public class GoodServiceImpl implements GoodsService {

    public GoodServiceImpl() {
        System.out.println("GoodServiceImpl 对象创建...");
    }

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    ApplicationContext applicationContext;

    @Override
    public Good selectOne(Good good) {
        return goodsMapper.selectOne(good);
    }

    @Override
    public int insert(Good good) {
        try {
            applicationContext.getBean(GoodsService.class).insert2(good);
        } catch (Exception e) {
            System.out.println("异常了！");
        }
        return 0;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void insert2(Good good) {
        goodsMapper.insert(good);
        throw new RuntimeException("11");
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public int insert0(Good good) {
        goodsMapper.insert(good);
        System.out.println(this);
        int i = 1 / 0;
        return 0;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = GoodException.class)
    public int insert1(Good good) {
        goodsMapper.insert(good);
        if (good.getGoodsId() > 10) {
            throw new GoodExceptionOver(">10");
        }
        if (good.getGoodsId() < 5) {
            throw new GoodException("<10");
        }
        return 0;
    }

    @Override
    public int insertList() {
        List<Good> goodList = IntStream.range(0, 2).mapToObj((i) -> {
            return new Good() {{
                setGoodsId(i);
                setGoodsName("STUDENT");
                setGoodsType(GoodType.STUDENT);
                setUserInfo(new UserInfo() {{
                    setAge(18);
                    setName("tang" + i);
                }});
            }};
        }).collect(Collectors.toList());
        goodsMapper.insertList(goodList);
        return 0;
    }

    @Resource
    SqlSessionFactory sessionFactory;

    ThreadPoolExecutor executor = new ThreadPoolExecutor(4, 6, 10000L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(10),new ThreadPoolExecutor.AbortPolicy());

    @Override
    public void threadInsert() {
        SqlSession sqlSession = SqlSessionUtils.getSqlSession(this.sessionFactory);
        GoodsMapper goodsMapper = sqlSession.getMapper(GoodsMapper.class);

        Connection connection = sqlSession.getConnection();
        ExceptionUtils.exceptionRun(Connection::setAutoCommit,connection,false);

        // 业务部分
        List<Good> result = IntStream.range(0, 100)
                .mapToObj(item -> {
                    Good good = new Good();
                    good.setGoodsId(item + 10);
                    good.setGoodsName("good" + item);
                    return good;
                }).collect(Collectors.toList());
        ArrayList<Callable<Integer>> callables = Lists.newArrayList();
        for (int i = 0; i < 5; i++) {
            int startIndex = i * 20;
            InsertTask insertTask =
                    new InsertTask(goodsMapper, result.subList(startIndex, startIndex + 19));
            insertTask.setIndex(3);
            callables.add(insertTask);
        }

        List<Future<Integer>> futures = ExceptionUtils.exceptionReturn(AbstractExecutorService::invokeAll, executor, callables).get();
        for (Future<Integer> future : futures) {
            Integer value = ExceptionUtils.exceptionReturn(Future::get, future).get();
            if (future.isDone() && value < 0) {
                ExceptionUtils.exceptionRun(Connection::rollback,connection);
                break;
            } else {
                ExceptionUtils.exceptionRun(Connection::commit,connection);
            }
        }
        ExceptionUtils.exceptionRun(Connection::close,connection);
    }

    static class InsertTask implements Callable<Integer> {

        GoodsMapper goodsMapper;

        List<Good> dataS;

        @Setter
        int index;

        public InsertTask(GoodsMapper goodsMapper, List<Good> datas) {
            this.goodsMapper = goodsMapper;
            this.dataS = datas;
        }

        @Override
        public Integer call() {
            try {
                if (index % 2 == 0) {
                    throw new RuntimeException(Thread.currentThread().getName() + " 手动异常发生！");
                }
                return goodsMapper.insertList(this.dataS);
            } catch (Exception e) {
                e.printStackTrace();
            }
            return -1;
        }
    }


}